home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / news / inn1.000 / inn1.4sec-linux-src.tar / inn / innd / rc.c < prev    next >
C/C++ Source or Header  |  1993-03-18  |  13KB  |  554 lines

  1. /*  $Revision: 1.31 $
  2. **
  3. **  Routines for the remote connect channel.  Create an Internet stream socket
  4. **  that processes connect to.  If the incoming site is not one of our feeds,
  5. **  then we pass the connection off to the standard nntp daemon.
  6. */
  7. #include "innd.h"
  8. #include <netdb.h>
  9.  
  10.  
  11. #if    !defined(NETSWAP)
  12. #if    !defined(htons)
  13. extern unsigned short    htons();
  14. #endif    /* !defined(htons) */
  15. #if    !defined(htonl)
  16. extern unsigned long    htonl();
  17. #endif    /* !defined(htonl) */
  18. #endif    /* !defined(NETSWAP) */
  19.  
  20. #define COPYADDR(dest, src) \
  21.         (void)memcpy((POINTER)dest, (POINTER)src, (SIZE_T)sizeof (INADDR))
  22.  
  23. /*
  24. **  A remote host has an address and a password.
  25. */
  26. typedef struct _REMOTEHOST {
  27.     char    *Name;
  28.     INADDR    Address;
  29.     char    *Password;
  30.     char    **Patterns;
  31. } REMOTEHOST;
  32.  
  33. STATIC INADDR        *RCmaster;
  34. STATIC int        RCnmaster;
  35. STATIC char        *RCslaveflag;
  36. STATIC char        RCnnrpd[] = _PATH_NNRPD;
  37. STATIC char        RCnnrqd[] = _PATH_NNQRD;
  38. STATIC char        RCnntpd[] = _PATH_NNTPD;
  39. STATIC CHANNEL        *RCchan;
  40. STATIC REMOTEHOST    *RCpeerlist;
  41. STATIC int        RCnpeerlist;
  42. STATIC REMOTEHOST    *RCnolimitlist;
  43. STATIC int        RCnnolimitlist;
  44.  
  45.  
  46. /*
  47. **  See if the site properly entered the password.
  48. */
  49. BOOL
  50. RCauthorized(cp, pass)
  51.     register CHANNEL    *cp;
  52.     char        *pass;
  53. {
  54.     register REMOTEHOST    *rp;
  55.     register int    i;
  56.  
  57.     for (rp = RCpeerlist, i = RCnpeerlist; --i >= 0; rp++)
  58.     /* SUPPRESS 112 *//* Retrieving long where char is stored */
  59.     if (cp->Address.s_addr == rp->Address.s_addr) {
  60.         if (rp->Password[0] == '\0' || EQ(pass, rp->Password))
  61.         return TRUE;
  62.         syslog(L_ERROR, "%s bad_auth", inet_ntoa(cp->Address));
  63.         return FALSE;
  64.     }
  65.  
  66.     if (!AnyIncoming)
  67.     /* Not found in our table; this can't happen. */
  68.     syslog(L_ERROR, "%s not_found", inet_ntoa(cp->Address));
  69.  
  70.     /* Anonymous hosts should not authenticate. */
  71.     return FALSE;
  72. }
  73.  
  74.  
  75. /*
  76. **  See if a host is in the "nolimit" file.
  77. */
  78. BOOL
  79. RCnolimit(cp)
  80.     register CHANNEL    *cp;
  81. {
  82.     register REMOTEHOST    *rp;
  83.     register int    i;
  84.  
  85.     for (rp = RCnolimitlist, i = RCnnolimitlist; --i >= 0; rp++)
  86.     /* SUPPRESS 112 *//* Retrieving long where char is stored */
  87.     if (cp->Address.s_addr == rp->Address.s_addr)
  88.         return TRUE;
  89.     return FALSE;
  90. }
  91.  
  92.  
  93. /*
  94. **  Is this an address of the master?
  95. */
  96. BOOL
  97. RCismaster(addr)
  98.     INADDR        addr;
  99. {
  100.     register INADDR    *ip;
  101.     register int    i;
  102.  
  103.     if (AmSlave)
  104.     for (i = RCnmaster, ip = RCmaster; --i >= 0; ip++)
  105.         /* SUPPRESS 112 *//* Retrieving long where char is stored */
  106.         if (addr.s_addr == ip->s_addr)
  107.         return TRUE;
  108.     return FALSE;
  109. }
  110.  
  111.  
  112. /*
  113. **  Hand off a descriptor to NNRPD.
  114. */
  115. void
  116. RChandoff(fd, h)
  117.     int        fd;
  118.     HANDOFF    h;
  119. {
  120.     STRING    argv[6];
  121.     char    buff[SMBUF];
  122.     int        i;
  123.  
  124.     if (SetNonBlocking(fd, FALSE) < 0)
  125.     syslog(L_ERROR, "%s cant nonblock %d in RChandoff %m", LogName, fd);
  126.     switch (h) {
  127.     default:
  128.     syslog(L_ERROR, "%s internal RChandoff %d type %d", LogName, fd, h);
  129.     /* FALLTHROUGH */
  130.     case HOnnrpd:    argv[0] = RCnnrpd;    break;
  131.     case HOnnrqd:    argv[0] = RCnnrqd;    break;
  132.     case HOnntpd:    argv[0] = RCnntpd;    break;
  133.     }
  134.     argv[1] = "-s                                                ";
  135.     i = 2;
  136.     if (NNRPReason) {
  137.     (void)sprintf(buff, "-r%s", NNRPReason);
  138.     argv[i++] = buff;
  139.     }
  140.     if (NNRPTracing)
  141.     argv[i++] = "-t";
  142.     if (RCslaveflag)
  143.     argv[i++] = RCslaveflag;
  144.     argv[i] = NULL;
  145.  
  146.     /* Call NNRP; don't send back a QUIT message if Spawn fails since  
  147.      * that's a major error we want to find out about quickly. */
  148.     (void)Spawn(fd, fd, fd, argv);
  149. }
  150.  
  151.  
  152. /*
  153. **  Read function.  Accept the connection and either create an NNTP channel
  154. **  or spawn an nnrpd to handle it.
  155. */
  156. STATIC FUNCTYPE
  157. RCreader(cp)
  158.     CHANNEL        *cp;
  159. {
  160.     int            fd;
  161.     struct sockaddr_in    remote;
  162.     int            size;
  163.     register int    i;
  164.     register REMOTEHOST    *rp;
  165.     CHANNEL        *new;
  166.     char        *name;
  167.  
  168.     if (cp != RCchan) {
  169.     syslog(L_ERROR, "%s internal RCreader wrong channel 0x%x not 0x%x",
  170.         LogName, cp, RCchan);
  171.     return;
  172.     }
  173.  
  174.     /* Get the connection. */
  175.     size = sizeof remote;
  176.     if ((fd = accept(cp->fd, (struct sockaddr *)&remote, &size)) < 0) {
  177.     syslog(L_ERROR, "%s cant accept RCreader %m", LogName);
  178.     return;
  179.     }
  180.  
  181.     /* See if it's one of our servers. */
  182.     for (name = NULL, rp = RCpeerlist, i = RCnpeerlist; --i >= 0; rp++)
  183.     /* SUPPRESS 112 *//* Retrieving long where char is stored */
  184.     if (rp->Address.s_addr == remote.sin_addr.s_addr) {
  185.         name = rp->Name;
  186.         break;
  187.     }
  188.  
  189.     /* If not a server, and not allowing anyone, hand him off. */
  190.     if (i >= 0)
  191.     new = NCcreate(fd, rp->Password[0] != '\0');
  192.     else if (AnyIncoming)
  193.     new = NCcreate(fd, FALSE);
  194.     else {
  195.     RChandoff(fd, HOnntpd);
  196.     if (close(fd) < 0)
  197.         syslog(L_ERROR, "%s cant close %d %m", LogName, fd);
  198.     return;
  199.     }
  200.  
  201.     /* SUPPRESS 112 *//* Retrieving long where char is stored */
  202.     new->Address.s_addr = remote.sin_addr.s_addr;
  203.     syslog(L_NOTICE, "%s connected %d",
  204.     name ? name : inet_ntoa(new->Address), new->fd);
  205. }
  206.  
  207.  
  208. /*
  209. **  Write-done function.  Shouldn't happen.
  210. */
  211. STATIC FUNCTYPE
  212. RCwritedone()
  213. {
  214.     syslog(L_ERROR, "%s internal RCwritedone", LogName);
  215. }
  216.  
  217.  
  218. /*
  219. **  Read in the file listing the hosts we take news from, and fill in the
  220. **  global list of their Internet addresses.  On modern systems a host can
  221. **  have multiple addresses, so we take care to add all of them to the list.
  222. **  We can distinguish between the two because h_addr is a #define for the
  223. **  first element of the address list in modern systems, while it's a field
  224. **  name in old ones.
  225. */
  226. STATIC void
  227. RCreadfile(list, count, filename)
  228.     REMOTEHOST        **list;
  229.     int            *count;
  230.     char        *filename;
  231. {
  232.     static char        NOPASS[] = "";
  233.     char        buff[SMBUF];
  234.     register FILE    *F;
  235.     register char    *p;
  236.     struct hostent    *hp;
  237.     register int    i;
  238.     register REMOTEHOST    *rp;
  239.     register int    j;
  240.     char        *pass;
  241.     char        *pats;
  242.     int            errors;
  243.  
  244.     /* Free anything that might have been there. */
  245.     if (*list) {
  246.     for (rp = *list, i = *count; --i >= 0; rp++) {
  247.         DISPOSE(rp->Name);
  248.         DISPOSE(rp->Password);
  249.         if (rp->Patterns)
  250.         DISPOSE(rp->Patterns);
  251.     }
  252.     DISPOSE(*list);
  253.     *list = NULL;
  254.     *count = 0;
  255.     }
  256.  
  257.     /* Open the server file, count the lines. */
  258.     if ((F = fopen(filename, "r")) == NULL) {
  259.     syslog(L_FATAL, "%s cant read %s %m", LogName, filename);
  260.     exit(1);
  261.     }
  262.     for (i = 1; fgets(buff, sizeof buff, F) != NULL; )
  263.     if (buff[0] != COMMENT_CHAR && buff[0] != '\n')
  264.         i++;
  265.     *count = i;
  266.     rp = *list = NEW(REMOTEHOST, *count);
  267. #if    !defined(DO_HAVE_UNIX_DOMAIN)
  268.     rp->Address.s_addr = inet_addr(LOOPBACK_HOST);
  269.     rp->Name = COPY("localhost");
  270.     rp->Password = COPY(NOPASS);
  271.     rp->Patterns = NULL;
  272.     rp++;
  273. #endif    /* !defined(DO_HAVE_UNIX_DOMAIN) */
  274.  
  275.     /* Now read the file to add all the hosts. */
  276.     (void)fseek(F, (OFFSET_T)0, SEEK_SET);
  277.     for (errors = 0; fgets(buff, sizeof buff, F) != NULL; ) {
  278.     /* Ignore blank and comment lines. */
  279.     if ((p = strchr(buff, '\n')) != NULL)
  280.         *p = '\0';
  281.     if ((p = strchr(buff, COMMENT_CHAR)) != NULL)
  282.         *p = '\0';
  283.     if (buff[0] == '\0')
  284.         continue;
  285.     if ((pass = strchr(buff, ':')) != NULL) {
  286.         *pass++ = '\0';
  287.         if ((pats = strchr(pass, ':')) != NULL)
  288.         *pats++ = '\0';
  289.         else
  290.         pats = NULL;
  291.     }
  292.     else {
  293.         pass = NOPASS;
  294.         pats = NULL;
  295.     }
  296.  
  297.     /* Was host specified as as dotted quad? */
  298.     if ((rp->Address.s_addr = inet_addr(buff)) != (unsigned long)-1) {
  299.         rp->Name = COPY(buff);
  300.         rp->Password = COPY(pass);
  301.         rp->Patterns = pats ? CommaSplit(COPY(pats)) : NULL;
  302.         rp++;
  303.         continue;
  304.     }
  305.  
  306.     /* Host specified as a text name? */
  307.     if ((hp = gethostbyname(buff)) == NULL) {
  308.         syslog(L_ERROR, "%s cant gethostbyname %s %m", LogName, buff);
  309.         errors++;
  310.         continue;
  311.     }
  312.  
  313. #if    defined(h_addr)
  314.     /* Count the addresses and see if we have to grow the list. */
  315.     for (i = 0; hp->h_addr_list[i]; i++)
  316.         continue;
  317.     if (i == 0) {
  318.         syslog(L_ERROR, "%s no_address %s %m", LogName, buff);
  319.         errors++;
  320.         continue;
  321.     }
  322.     if (i == 1) {
  323.         /* Just one, no need to grow. */
  324.         COPYADDR(&rp->Address, hp->h_addr_list[0]);
  325.         rp->Name = COPY(hp->h_name);
  326.         rp->Password = COPY(pass);
  327.         rp->Patterns = pats ? CommaSplit(COPY(pats)) : NULL;
  328.         rp++;
  329.         continue;
  330.     }
  331.  
  332.     /* Note the relative position, grow the array, and restore it. */
  333.     j = rp - *list;
  334.     *count += i - 1;
  335.     RENEW(*list, REMOTEHOST, *count);
  336.     rp = *list + j;
  337.  
  338.     /* Add all the hosts. */
  339.     for (i = 0; hp->h_addr_list[i]; i++) {
  340.         COPYADDR(&rp->Address, hp->h_addr_list[i]);
  341.         rp->Name = COPY(hp->h_name);
  342.         rp->Password = COPY(pass);
  343.         rp->Patterns = pats ? CommaSplit(COPY(pats)) : NULL;
  344.         rp++;
  345.     }
  346. #else
  347.     /* Old-style, single address, just add it. */
  348.     COPYADDR(&rp->Address, hp->h_addr);
  349.     rp->Name = COPY(hp->h_name);
  350.     rp->Password = COPY(pass);
  351.     rp->Patterns = pats ? CommaSplit(COPY(pats)) : NULL;
  352.     rp++;
  353. #endif    /* defined(h_addr) */
  354.     }
  355.     *count = rp - *list;
  356.  
  357.     if (fclose(F) == EOF)
  358.     syslog(L_ERROR, "%s cant fclose %s %m", LogName, filename);
  359.  
  360.     if (errors)
  361.     syslog(L_ERROR, "%s bad_hosts %d in %s", LogName, errors, filename);
  362. }
  363.  
  364.  
  365. void
  366. RCreadlist()
  367. {
  368.     static char    INNDHOSTS[] = _PATH_INNDHOSTS;
  369.     char    name[sizeof _PATH_INNDHOSTS + sizeof ".nolimit"];
  370.     struct stat    Sb;
  371.  
  372.     RCreadfile(&RCpeerlist, &RCnpeerlist, INNDHOSTS);
  373.     FileGlue(name, INNDHOSTS, '.', "nolimit");
  374.     if (stat(name, &Sb) >= 0)
  375.     RCreadfile(&RCnolimitlist, &RCnnolimitlist, name);
  376. }
  377.  
  378.  
  379.  
  380. /*
  381. **  Find the name of a remote host we've connected to.
  382. */
  383. char *
  384. RChostname(cp)
  385.     register CHANNEL    *cp;
  386. {
  387.     static char        buff[SMBUF];
  388.     register REMOTEHOST    *rp;
  389.     register int    i;
  390.  
  391.     for (rp = RCpeerlist, i = RCnpeerlist; --i >= 0; rp++)
  392.     /* SUPPRESS 112 *//* Retrieving long where char is stored */
  393.     if (cp->Address.s_addr == rp->Address.s_addr)
  394.         return rp->Name;
  395.     (void)strcpy(buff, inet_ntoa(cp->Address));
  396.     return buff;
  397. }
  398.  
  399.  
  400. /*
  401. **  Is the remote site allowed to post to this group?
  402. */
  403. BOOL
  404. RCcanpost(cp, group)
  405.     register CHANNEL    *cp;
  406.     register char    *group;
  407. {
  408.     register REMOTEHOST    *rp;
  409.     register BOOL    match;
  410.     register BOOL    subvalue;
  411.     register char    **argv;
  412.     register char    *pat;
  413.     register int    i;
  414.  
  415.     for (rp = RCpeerlist, i = RCnpeerlist; --i >= 0; rp++) {
  416.     /* SUPPRESS 112 *//* Retrieving long where char is stored */
  417.     if (cp->Address.s_addr != rp->Address.s_addr)
  418.         continue;
  419.     if (rp->Patterns == NULL)
  420.         break;
  421.     for (match = TRUE, argv = rp->Patterns; (pat = *argv++) != NULL; ) {
  422.         subvalue = *pat != SUB_NEGATE;
  423.         if (!subvalue)
  424.         pat++;
  425.         if (wildmat(group, pat))
  426.         match = subvalue;
  427.     }
  428.     return match;
  429.     }
  430.     return TRUE;
  431. }
  432.  
  433.  
  434. /*
  435. **  Create the channel.
  436. */
  437. void
  438. RCsetup(i, master)
  439.     register int    i;
  440.     char        *master;
  441. {
  442.     struct sockaddr_in    server;
  443.     struct hostent    *hp;
  444.     INADDR        a;
  445.     char        buff[SMBUF];
  446. #if    defined(SO_REUSEADDR)
  447.     int            on;
  448. #endif    /* defined(SO_REUSEADDR) */
  449.  
  450.     if (i < 0) {
  451.     /* Create a socket and name it. */
  452.     if ((i = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
  453.         syslog(L_FATAL, "%s cant socket RCreader %m", LogName);
  454.         exit(1);
  455.     }
  456. #if    defined(SO_REUSEADDR)
  457.     on = 1;
  458.     if (setsockopt(i, SOL_SOCKET, SO_REUSEADDR,
  459.         (caddr_t)&on, sizeof on) < 0)
  460.         syslog(L_ERROR, "%s cant setsockopt RCreader %m", LogName);
  461. #endif    /* defined(SO_REUSEADDR) */
  462.     (void)memset((POINTER)&server, 0, sizeof server);
  463.     server.sin_port = htons(NNTP_PORT);
  464.     server.sin_family = AF_INET;
  465.     server.sin_addr.s_addr = htonl(INADDR_ANY);
  466.     if (bind(i, (struct sockaddr *)&server, sizeof server) < 0) {
  467.         syslog(L_FATAL, "%s cant bind RCreader %m", LogName);
  468.         exit(1);
  469.     }
  470.     }
  471.  
  472.     /* Set it up to wait for connections. */
  473.     if (listen(i, MAXLISTEN) < 0) {
  474.     syslog(L_FATAL, "%s cant listen RCreader %m", LogName);
  475.     exit(1);
  476.     }
  477.     RCchan = CHANcreate(i, CTremconn, CSwaiting, RCreader, RCwritedone);
  478.     syslog(L_NOTICE, "%s rcsetup %s", LogName, CHANname(RCchan));
  479.     RCHANadd(RCchan);
  480.  
  481.     /* Get the list of hosts we handle. */
  482.     RCreadlist();
  483.  
  484.     /* If we have a master, get all his addresses. */
  485.     AmSlave = master != NULL;
  486.     if (AmSlave) {
  487.     /* Dotted quad? */
  488.     if ((a.s_addr = inet_addr(master)) != (unsigned long)-1) {
  489.         RCnmaster = 1;
  490.         RCmaster = NEW(INADDR, 1);
  491.         COPYADDR(&RCmaster[0], &a);
  492.     }
  493.     else {
  494.         /* Must be a text name. */
  495.         if ((hp = gethostbyname(master)) == NULL) {
  496.         syslog(L_FATAL, "%s cant gethostbyname %s %m", LogName, master);
  497.         exit(1);
  498.         }
  499. #if    defined(h_addr)
  500.         /* Count the addresses. */
  501.         for (i = 0; hp->h_addr_list[i]; i++)
  502.         continue;
  503.         if (i == 0) {
  504.         syslog(L_FATAL, "%s no_address %s %m", LogName, master);
  505.         exit(1);
  506.         }
  507.         RCnmaster = i;
  508.         RCmaster = NEW(INADDR, RCnmaster);
  509.         for (i = 0; hp->h_addr_list[i]; i++)
  510.         COPYADDR(&RCmaster[i], hp->h_addr_list[i]);
  511. #else
  512.         RCnmaster = 1;
  513.         RCmaster = NEW(INADDR, 1)
  514.         COPYADDR(&RCmaster[0], &a);
  515. #endif    /* defined(h_addr) */
  516.     }
  517.  
  518.     /* Set flag for nnrp. */
  519.     (void)sprintf(buff, "-S%s", master);
  520.     RCslaveflag = COPY(buff);
  521.     }
  522. }
  523.  
  524.  
  525. /*
  526. **  Cleanly shut down the channel.
  527. */
  528. void
  529. RCclose()
  530. {
  531.     register REMOTEHOST    *rp;
  532.     register int    i;
  533.  
  534.     CHANclose(RCchan, CHANname(RCchan));
  535.     RCchan = NULL;
  536.     if (RCpeerlist) {
  537.     for (rp = RCpeerlist, i = RCnpeerlist; --i >= 0; rp++) {
  538.         DISPOSE(rp->Name);
  539.         DISPOSE(rp->Password);
  540.         if (rp->Patterns)
  541.         DISPOSE(rp->Patterns);
  542.     }
  543.     DISPOSE(RCpeerlist);
  544.     RCpeerlist = NULL;
  545.     RCnpeerlist = 0;
  546.     }
  547.  
  548.     if (RCmaster) {
  549.     DISPOSE(RCmaster);
  550.     RCmaster = NULL;
  551.     RCnmaster = 0;
  552.     }
  553. }
  554.